package com.cc.visitor.utils;

import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.*;
import com.cc.alltype.BusinessException;
import com.cc.alltype.wechat.MiniGetUserProfileRes;
import com.cc.alltype.wechat.QrType;
import com.cc.alltype.wechat.SceneQRTicketRes;
import com.cc.alltype.wechat.WechatQrSceneUtils;
import com.cc.visitor.dao.ConfigMapper;
import com.cc.visitor.dao.LoginQrLogMapper;
import com.cc.visitor.entity.Config;
import com.cc.visitor.entity.LogError;
import com.cc.visitor.entity.LoginQrLog;
import com.cc.visitor.entity.UserWeixin;
import com.cc.visitor.entity.wechat.*;
import com.cc.visitor.enums.DevMaterial;
import com.cc.visitor.enums.LogErrorModule;
import com.cc.visitor.enums.QrUseType;
import com.cc.visitor.service.LogErrorService;
import com.cc.visitor.service.UserWeixinService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sun.media.sound.SoftMixingSourceDataLine;
import com.thoughtworks.xstream.XStream;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import javax.annotation.PostConstruct;

/**
 * @author chanchaw
 * @create 2024-09-19 21:49
 */
@Component
public class WechatUtils {
    @Autowired
    private ConfigMapper configMapper;
    private static final Logger logger = LoggerFactory.getLogger("wxmp");
    private static final ObjectMapper mapper = new ObjectMapper();
    @Autowired
    private LoginQrLogMapper loginQrLogMapper;
    @Autowired
    private TemplateMsgUtils templateMsgUtils;
    @Autowired
    private UserWeixinService userWeixinService;
//    private ObjectMapper mapper = null;
    @Autowired
    private WxAccessToken wxAccessToken;
    @Autowired
    private LogErrorService logErrorService;
    @Autowired
    private RestTemplateUtils restTemplateUtils;

//    @PostConstruct
//    public void init(){
//        mapper = new ObjectMapper();
//    }

    /**
     * 2024年11月9日 16:16:47 微信服务号处理用户请求
     * @param is
     * @return
     * @throws IOException
     */
    public String getResponse(InputStream is) throws Exception {
        logger.info("WechatUtils#getResponse");
        Map<String,String> map = parseRequest(is);
        logger.info("消息内容：{}", map.toString());
        String msgType = map.get("MsgType");
        WechatBaseMassage bm = null;

        switch (msgType){
            case "text":
                bm = resText(map);
                break;
            case "image":
                break;
            case "voice":
                break;
            case "video":
                break;
            case "shortvideo":
                break;
            case "location":
                break;
            case "link":
                break;
            case "event":// 处理事件，多数情况是处理扫描关注
                bm = resEvent(map);
                break;
            default:
                break;
        }

        XStream stream = new XStream();
        // 按照指定类型将对象序列化为 xml
        stream.processAnnotations(WechatTextMessage.class);
//        stream.processAnnotations(Article.class);
//        stream.processAnnotations(ImgMessage.class);
//        stream.processAnnotations(Music.class);
//        stream.processAnnotations(MusicMessage.class);
//        stream.processAnnotations(NewsMessage.class);
//        stream.processAnnotations(VideoMessage.class);
//        stream.processAnnotations(VoiceMessage.class);

        String retXML = "";
        if ( bm == null ) return "";
        retXML = stream.toXML(bm);
        return retXML;
    }

    public MiniGetUserProfileRes getUserProfile(String code) throws JsonProcessingException {
        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        map.put("appid", new ArrayList<>(Arrays.asList(DevMaterial.VISITOR_MINI.APPID)));
        map.put("secret", new ArrayList<>(Arrays.asList(DevMaterial.VISITOR_MINI.APPSECRET)));
        map.put("js_code", new ArrayList<>(Arrays.asList(code)));
        map.put("grant_type", new ArrayList<>(Arrays.asList("authorization_code")));
        MiniGetUserProfileRes res = restTemplateUtils.postForm("https://api.weixin.qq.com/sns/jscode2session", map, MiniGetUserProfileRes.class);
        String msg = "";
        if(res == null){
            msg = "使用code:" + code + "，执行微信小程序登录时得到相应结果为NULL";
            System.out.println(msg);
            throw new BusinessException(msg);
        }
        // 如果请求出错
        Integer errcode = Optional.ofNullable(res.getErrcode()).orElse(0);
        if(errcode != 0) {
            logErrorService.insert(
                LogError.builder()
                        .module(LogErrorModule.BACKEND.getSid())
                        .func("WechatUtils.getUserProfile")
                        .errMsg(res.getErrmsg())
                        .remark("code:" + code)
                        .build()
            );
            throw new BusinessException("使用code:" + code + "，执行小程序登录时响应了错误码" + errcode + "，错误消息：" + res.getErrmsg());
        }
        return res;
    }

    public UserWeixin getUserWeixin(String code) throws JsonProcessingException {
        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        map.put("appid", new ArrayList<>(Arrays.asList(DevMaterial.VISITOR_MINI.APPID)));
        map.put("secret", new ArrayList<>(Arrays.asList(DevMaterial.VISITOR_MINI.APPSECRET)));
        map.put("js_code", new ArrayList<>(Arrays.asList(code)));
        map.put("grant_type", new ArrayList<>(Arrays.asList("authorization_code")));
        MiniGetUserProfileRes res = restTemplateUtils.postForm("https://api.weixin.qq.com/sns/jscode2session", map, MiniGetUserProfileRes.class);
        if(res == null) {
            System.out.println("请求用户openId时接收到NULL响应");
            logger.info("使用code" + code + "请求微信用户信息时响应了NULL");
            throw new BusinessException("请求用户openId时接收到NULL响应");
        }
        Integer errcode = Optional.ofNullable(res.getErrcode()).orElse(0);
        if(errcode != 0) {
            System.out.println("请求用户openId时出错:" + res.toString());
            logger.info("使用code" + code + "请求微信用户信息时响应了错误码：" + errcode + "，报错信息：" + res.getErrmsg());
            throw new BusinessException("请求用户openId时出错：" + res.getErrmsg());
        }
        String miniId = res.getOpenid();
        UserWeixin userWeixin = userWeixinService.select8MiniId(miniId);
        return userWeixin;
    }

    /**
     * 通过签名验证微信服务器的身份，从微信服务器发送来的请求中提取参数后校验是否合法的微信服务器
     * @param timestamp
     * @param nonce
     * @param signature
     * @return
     */
    public static boolean checkServer(String timestamp,String nonce,String signature) {
        // 1. 将token、timestamp、nonce三个参数进行字典序排序
        String[] strs = new String[] { DevMaterial.VISITOR_MINI.TOKEN,timestamp,nonce };

        //2. 将数组中的元素排序后形成字符串等待加密
        Arrays.sort(strs);
        String str = strs[0] + strs[1] + strs[2];

        // 3. 加密后的字符串与signature对比，相同则来源于微信
        String ciphertext = sha1(str);
        return ciphertext.equalsIgnoreCase(signature);
    }
    /**
     * 进行 SHA1 加密，返回加密后的字符串
     * @param src 被加密的文本
     * @return 返回加密后的密文
     */
    private static String sha1(String src) {
        try {
            MessageDigest md = MessageDigest.getInstance("sha1");
            byte[] digest = md.digest(src.getBytes());
            char[] chars = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };

            StringBuilder sb = new StringBuilder();
            for( byte b:digest ) {
                sb.append(chars[(b>>4)&15]);
                sb.append(chars[b&15]);
            }

            return sb.toString();
        } catch (NoSuchAlgorithmException e) {

            e.printStackTrace();
        }

        return null;
    }

    /**
     * 用户发送来的 http 请求中将 InputStream 类型数据
     * 转换为 Map 类型并返回，之后可以通过查询键值 MsgType
     * 得知用户发来的是什么类型的请求
     * 用户在服务号发送文本则 MsgType = text
     * 发送图片 MsgType = image
     * 声音 MsgType = voice
     * video = 视频,shortvideo = 短视频,location = 位置，link = 连接
     * event 表示事件，又分为多种事件：subscribe、unsubscribe、CLICK、SCAN
     * 依次表示：关注、取消关注、点击菜单、扫描服务号二维码（即使关注过了也会触发本事件）
     * @param is 用户发送来的请求的数据
     * @return 返回类型 Map<String,String> 的数据
     */
    public static Map<String, String> parseRequest(InputStream is ) {
        Map<String, String> map = new HashMap<>();
        SAXReader reader = new SAXReader();
        try {
            Document doc = reader.read(is);
            Element root = doc.getRootElement();
            List<Element> eles = root.elements();

            for (Element e : eles) {
                map.put(e.getName(), e.getStringValue());
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }

        return map;
    }
    public static WechatTextMessage resText(Map<String,String> map, String msgContent){
        return new WechatTextMessage(map, msgContent);
    }

    public static WechatTextMessage resText(Map<String,String> map){
        String content = map.get("Content");
        StringBuilder sb = new StringBuilder();
        switch (content){
            case "测试":
                sb.append("精之研测试 WechatTextMessage 成功");
                break;
            case "抬头":
                sb.append("精之研");
                break;
            case "测试日志":
                sb.append("");
                break;
            case "测试业务数据库":
                sb.append("");
                break;
            default:
                sb.append("");
                break;
        }

        String text = sb.toString();
        return (text.length()<=0)?null:new WechatTextMessage(map,sb.toString());
    }

    private WechatBaseMassage resEvent(Map<String,String> map) throws Exception {
        String event = map.get("Event");
        WechatBaseMassage bm = null;


        switch (event){
            case "subscribe":// 关注事件
                bm = handleSubscribe(map);
                //bm = resText(map, subscribeResMsg);
                break;
            case "unsubscribe":// 取消关注事件
                break;
            case "CLICK":// 点击菜单项事件

                break;
            case "SCAN":// 扫描二维码事件
//                pushMsg2RealNamePage(map);// 处理第二次关联
                bm = handleScan(map);
                break;
            case "view_miniprogram":
                bm = clickRegister(map);
                break;
            default:
                break;
        }
        return bm;
    }

    /**
     * 使用前端传递来的参数请求微信服务器获取二维码ticket
     * @param qrType 0临时二维码，1永久二维码
     * @param sceneStr 1,0,10 = 永久二维码,关注用二维码,普通访客
     * @return
     */
    public SceneQRTicketRes getQRTicket(QrType qrType, String sceneStr){
        Map reqMap = null;
        if(qrType.equals(QrType.TEMP)) reqMap = WechatQrSceneUtils.getTempTicketReqParamMap(sceneStr);
//        if(qrType.equals(QrType.TEMP))
//            reqMap = getTempTicketReqParamMap(sceneStr);
        if(qrType.equals(QrType.PERMANENT)) reqMap = WechatQrSceneUtils.getPermanentTicketReqParamMap(sceneStr);
        if(reqMap == null) throw new BusinessException("二维码只有两种类型：临时、永久");

        SceneQRTicketRes res = null;
        try {
            String token = wxAccessToken.getAccessToken();
            String url = WechatQrSceneUtils.getQrTicketUrl(token);
            res = restTemplateUtils.postJson(url, reqMap, SceneQRTicketRes.class);
        } catch (JsonProcessingException e) {
            logger.info("请求临时二维码ticket时出现异常：" + e.getMessage());
        }

        // 如果返回异常则请求出错信息
        try {
            handleRid(res);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        return res;
    }

    /**
     * 处理用户扫描二维码事件，二维码场景值 map 对象实际是 CreateQrTicketReqParam 对象
     * 所以需要根据属性 type 做不同的逻辑处理：0表示关注用二维码
     * @param map
     */
    private WechatBaseMassage handleScan(Map<String,String> map) throws Exception {
        logger.info("用户扫描二维码传递来的参数：" + map.toString());
        String openId = WechatMapUtils.getOpenId(map);
        String eventKey = Optional.ofNullable(map.get("EventKey")).orElse("");
        if(eventKey.length() == 0) {
            logger.info("扫描的二维码没有场景值，退出本方法 handleScan");
            return null;
        }
        // eventKey = 1,0,10 = 永久二维码,用于关注的二维码,普通访客
        // eventKey = 1,0,11 = 永久二维码,用于关注的二维码,贵宾访客
        String[] split = eventKey.split(",");
        Integer qrUseTypeId = Integer.parseInt(split[1]);
        QrUseType qrUseType = QrUseType.ofid(qrUseTypeId);

        if(qrUseType.equals(QrUseType.FOLLOW))// 扫描关注
            return handleScanFollow(map);
        else if(qrUseType.equals(QrUseType.BROWSER_LOGIN))// 扫描浏览器二维码登录
            return handleScanLogin(eventKey, openId);
        throw new BusinessException("未定义的二维码类型，无法处理扫描请求！");
    }

    /**
     * 处理扫描登录二维码的逻辑，
     * @param sceneData 二维码场景值
     *                  类似：1,0,10 = 【永久，关注用，普通访客】二维码
     *                  类似：0,3,c0892608-560d-4dd4-86ad-dfde5f3642c9 = 【临时，登录用，UUI】二维码
     * @param openId 微信用户在服务号中的 openId
     */
    private WechatBaseMassage handleScanLogin(String sceneData, String openId){
        sceneData = Optional.ofNullable(sceneData).orElse("");
        if(sceneData.length() == 0) return null;
        String[] split = sceneData.split(",");
        String uuid = split[split.length-1];
        List<LoginQrLog> loginQrLogs = loginQrLogMapper.select8uuid(uuid);
        if(loginQrLogs == null || loginQrLogs.size() == 0) return null;

        LoginQrLog loginQrLog1 = loginQrLogs.get(0);
        UserWeixin userWeixin = userWeixinService.select8OpenId(openId);
        if(userWeixin == null) {
            loginQrLog1.setMsg("只有本厂内部员工可以登录，请向管理员索要注册用二维码！");
            loginQrLogMapper.insert(loginQrLog1);
            return null;
        }
        Boolean interviewee = SystemUtils.isInterviewee(userWeixin);
        Boolean me = SystemUtils.isMe(userWeixin);
        if(!interviewee && !me) {
            loginQrLog1.setMsg("访客身份无法登录，只有本厂人员可以登录系统！");
            loginQrLogMapper.insert(loginQrLog1);
            return null;
        }

        for (LoginQrLog loginQrLog : loginQrLogs) {
            loginQrLog.setOpenId(openId);
            loginQrLog.setScanTime(LocalDateTime.now());
            loginQrLogMapper.update(loginQrLog);
        }
        return null;
    }

    // 处理关注逻辑
    private WechatBaseMassage handleSubscribe(Map<String, String> map){
        Integer qrSceneUserType = WechatMapUtils.getSceneUserType(map);
        String openId = WechatMapUtils.getOpenId(map);
        UserWeixin userWeixin = new UserWeixin();
        userWeixin.setOpenId(openId);
        userWeixin.setType(qrSceneUserType);
        // 获取用户 unionId
        String unionId = getUnionId(openId);
        userWeixin.setUnionId(unionId);
        //userWeixinService.insert8openId(userWeixin);// openId已经存在则不会新增，直接返回查询到的该用户
        templateMsgUtils.pushRegister(openId, qrSceneUserType);// 新用户关注后推送给其关注用模板消息
        Config config = configMapper.get8sid("关注后提醒用户注册的文案");
        return resText(map, config.getDatas());
    }

    // 处理扫描关注用二维码
    private WechatBaseMassage handleScanFollow(Map<String, String> map) throws Exception {
        String s = map.get("EventKey");
        if(s == null || s.length() == 0){
            logger.info("没有场景值，不做后续处理！");
            return null;
        }
        String openId = map.get("FromUserName");
        UserWeixin userWeixin = userWeixinService.select8OpenId(openId);
        if(userWeixin == null){
            logger.info("没有找到openId=" + openId + "的用户！");
            return null;
        }

        // 如果是开发人员，响应给其微信当前二维码的场景值
        Boolean isDev = userWeixinService.isDev(openId);
        if(isDev == false) {
            logger.info("不是开发人员，不返回场景值。");
            return null;
        }
        logger.info("开发人员扫描二维码，即将返回给其场景值：" + s);
        WechatTextMessage wechatTextMessage = new WechatTextMessage(map, "二维码场景值：" + s);
        return wechatTextMessage;
    }

    private RidInfo getRidInfo(String rid) throws JsonProcessingException {
        HashMap<String, Object> map = new HashMap<>();
        map.put("rid", rid);
        String url = "https://api.weixin.qq.com/cgi-bin/openapi/rid/get?access_token=ACCESS_TOKEN";
        url = url.replaceAll("ACCESS_TOKEN", wxAccessToken.getAccessToken());
        RidInfo ridInfo = restTemplateUtils.postJson(url, map, RidInfo.class);
        return ridInfo;
    }

    /**
     * 请求二维码票据返回异常的话，从中获取rid并返回
     * @param res
     * @return
     */
    private String getRid(SceneQRTicketRes res){
        String errmsg = res.getErrmsg();
        if(errmsg == null || errmsg.length() == 0) return null;
        String[] split = errmsg.split(":");
        String rid = split[split.length-1];
        return rid.trim();
    }

    private void handleRid(SceneQRTicketRes res) throws JsonProcessingException {
        Integer errcode = Optional.ofNullable(res.getErrcode()).orElse(0);
        if(errcode <= 0) return;

        String rid = getRid(res);
        RidInfo ridInfo = getRidInfo(rid);
        String msg = "微信服务器报错：" + ridInfo.toString();
        logger.info(msg);
        System.out.println(msg);
    }

    /**
     * 微信服务号中通过 openId 获取 unionId
     * @param openId 微信用户 openId
     * @return 返回用户 unionId
     */
    public String getUnionId(String openId){
        String tmp = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
        String url = tmp.replace("ACCESS_TOKEN", wxAccessToken.getAccessToken()).replace("OPENID", openId);
        GetUnionIdRes res = restTemplateUtils.get4Object(url, GetUnionIdRes.class);
        if(res == null) return "";
        return res.getUnionid();
    }

    // 根据用户 openId 获取用户简单信息
    public GetUnionIdRes getUserInfoSimple(String openId){
        String tmp = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
        String url = tmp.replace("ACCESS_TOKEN", wxAccessToken.getAccessToken()).replace("OPENID", openId);
        return restTemplateUtils.get4Object(url, GetUnionIdRes.class);
    }

    /**
     * 获取二维码URL
     * @param qrType 二维码类型：0临时，1永久
     * @param sceneStr 二维码内容字符串
     * @return
     */
    public String getQRUrl(QrType qrType, String sceneStr){
        SceneQRTicketRes qrTicket = getQRTicket(qrType, sceneStr);
        String ticket = qrTicket.getTicket();
        String encodedTicket = URLEncoder.encode(ticket);
        return "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + encodedTicket;
    }

    // 为小程序鉴定是否微信服务器
    public static boolean checkServerMini(String timestamp,String nonce,String signature) {
        // 1. 将token、timestamp、nonce三个参数进行字典序排序
        String[] strs = new String[] { DevMaterial.VISITOR_MINI.TOKEN,timestamp,nonce };

        //2. 将数组中的元素排序后形成字符串等待加密
        Arrays.sort(strs);
        String str = strs[0] + strs[1] + strs[2];

        // 3. 加密后的字符串与signature对比，相同则来源于微信
        String ciphertext = sha1(str);
        return ciphertext.equalsIgnoreCase(signature);
    }
    public static String getMpOpenId8Code(String code){
        System.out.println("微信服务号中通过code:" + code + "获取微信用户信息");
        String openidUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=APPSECRET&code=CODE&grant_type=authorization_code";
        String requestUrl = openidUrl.replace("APPID", DevMaterial.SHOWA_SERV.APPID).replace("APPSECRET", DevMaterial.SHOWA_SERV.APPSECRET).replace("CODE", code);

        String result = HttpUtils.sendGet(requestUrl);
        System.out.println("使用code请求微信用户信息得到的响应是：" + result);
        WebAuthorizeResult openidResult = null;
        try {
            openidResult = mapper.readValue(result, WebAuthorizeResult.class);
        } catch (JsonProcessingException e) {
            System.out.println("使用code获取微信用户信息解析为 WebAuthorizeResult 对象时出现异常：" + e.getMessage());
            throw new RuntimeException(e);
        }
        WechatWebAuthorityUtils.resolveErrorCode(openidResult.getErrcode());// 处理错误代码
        if( openidResult == null ){
            throw new BusinessException("使用code请求openid发送get请求后获得了空数据");
        }
        return openidResult.getOpenid();
    }
    // 生成微信服务号的签名
    public static Signature getWxmpSignature() {
        String nonce = "chanchaw";
        String timestamp = String.valueOf(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli());
        // 1. 将token、timestamp、nonce三个参数进行字典序排序
        String[] strs = new String[] { DevMaterial.SHOWA_SERV.TOKEN, timestamp, nonce };

        //2. 将数组中的元素排序后形成字符串等待加密
        Arrays.sort(strs);
        String str = strs[0] + strs[1] + strs[2];

        // 3. 加密后的字符串与signature对比，相同则来源于微信
        String signature = sha1(str);
        Signature ret = Signature.builder().timestamp(timestamp).nonceStr(nonce).signature(signature).build();
        System.out.println("请求来的服务号的签名对象：" + ret.toString());
        return ret;
    }
    private WechatBaseMassage clickRegister(Map<String,String> map){// 点击注册按钮
        logger.info("点击注册按钮微信服务器传来的参数：" + map.toString());
        System.out.println("点击注册按钮微信服务器传来的参数：" + map.toString());

        String s = map.get("EventKey");
        if(!s.equalsIgnoreCase("pages/register/register")) {
            System.out.println("点击的不是注册按钮");
            return null;
        }

        String openId = WechatMapUtils.getOpenId(map);
        GetUnionIdRes userInfoSimple = getUserInfoSimple(openId);
        if(userInfoSimple == null) return null;
        String unionId = Optional.ofNullable(userInfoSimple.getUnionid()).orElse("");
        if(unionId.length() == 0) return null;

        UserWeixin userWeixin = userWeixinService.get8UnionId(unionId);
        /**
         * 新用户没有通过扫描二维码关注（用户通过搜索找到服务号并关注）
         * 在服务号中点击 “新用户注册” 跳转到小程序进行注册
         * 此时先将用户的服务号 openId 和 unionId 新增到 DB
         * 之后在小程序中注册时再通过搜索 unionId 补充小程序 openId
         */
        Instant instant = Instant.ofEpochMilli(userInfoSimple.getSubscribe_time());
        LocalDateTime subscribeTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

        if(userWeixin == null) {
            UserWeixin build = UserWeixin.builder().openId(openId).unionId(unionId)
                    .qrScene(userInfoSimple.getQr_scene_str())
                    .subscribeTime(subscribeTime)
                    .sysRemark("服务号菜单项【新用户注册】新增本数据")
                    .build();
            userWeixinService.insert(build);
            return null;
        }
        String openId1 = Optional.ofNullable(userWeixin.getOpenId()).orElse("");
        if(openId1.length() == 0) {
            userWeixin.setOpenId(openId);
            userWeixinService.update(userWeixin);
        }
        return null;
    }

    /**
     * 获取带有微信服务号 APPID 签名的 H5页面地址，在该地址中可获取 code
     * 再通过 code 获取微信用户信息
     * @param url web页面原始地址，例如：https://showawx.xdfznh.club/wxmp/register.html
     * @return
     */
    public static String getMpH5Url(String url){
        String encodedUrl = URLEncoder.encode(url);
        return "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" +
                DevMaterial.SHOWA_SERV.APPID +
                "&redirect_uri=" + encodedUrl + "&response_type=code&scope=snsapi_base&state=1#wechat_redirect";
    }

    /**
     * 访客系统微信用户访问服务号H5页面收集用户信息后发送给开发人员
     * @param code H5页面code
     */
    public void notifyDevUserweixin(String code){
        String openId = Optional.ofNullable(getMpOpenId8Code(code)).orElse("");
        UserWeixin userWeixin = userWeixinService.select8OpenId(openId);

    }
}
